package cn.bonoon.kernel.support.searcher;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.ConcurrentModificationException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;

import cn.bonoon.kernel.bytecode.ASMQueryParser;
import cn.bonoon.kernel.events.ReadEvent;
import cn.bonoon.kernel.expression.ExpressionObject;
import cn.bonoon.kernel.expression.QueryConditionExpressionParser;
import cn.bonoon.kernel.expression.ExpressionValue;
import cn.bonoon.kernel.query.Pageable;
import cn.bonoon.kernel.support.ProxyEntityManager;
import cn.bonoon.kernel.support.models.AjaxNode;
import cn.bonoon.kernel.support.models.Item;
import cn.bonoon.kernel.support.models.Node;
import cn.bonoon.kernel.support.models.Page;
import cn.bonoon.kernel.util.StringHelper;

/**
 * <pre>
 * 标准的查询对象
 * 扩展自动转值的查询对象为{@link ExtendFinder}
 * 
 * {@link Finder}是“一次性”的对象，也就是说在本次的查询有效，下一次的查询将会创建新的{@link Finder}对象；
 * 所以这里的值需要考虑到这个临时性的特点，不能赋值后就认为这些值一直能用的
 * </pre>
 * @author jackson
 *
 */
public class StandardFinder implements Finder, Iterable<Object>{
	
	/** <pre>是否允许添加排序的语句；
	 * 
	 * 如果该实体对象被定义为“有序”的，则不允许外部使用排序的语句 </pre> */
	public boolean allowAppendOrder = true;
	
	/** hql语句 */
	public final StringBuilder from, where, orderby;
	
	/** 该语句的参数，也就是<code>x.user.id=?</code>语句里的"?"的参数值 */
	protected transient Object[] parameters;
	
	/** 参数的大小 */
	protected int size = 0;
	
	/** 如果使用分页，这里是分页的一些信息 */
	public Pageable pageable;
	
	/** 用于访问数据库的对象 */
	protected final ProxyEntityManager manager;
	
	/** 对查询到的结果列表的每一个对象都调用一次{@link FinderHandler#doHandler(Object, Object)}进行处理 */
	protected FinderHandler handler;
	
	//用于缓存和处理使用join连接的情况
	private Map<String, String> joinMapped;
	
	//表达式需要的字段，在一次查询中，这些字段都需要有值，如果没有则将会使用默认值
	//并且字段所在的位置必须与parameters中的位置顺序一致
	private ExpressionValue[] values = new ExpressionValue[0];
	
	/** 合并表达式 */
	public void combineExpression(QueryConditionExpressionParser expressionParser){
		if(null != expressionParser){
			Map<String, String> jm = expressionParser.joinMapped();
			if(null != jm && !jm.isEmpty()){
				if(null == joinMapped){
					joinMapped = new HashMap<>();
				}
				joinMapped.putAll(jm);
			}
			values = expressionParser.values();
			size = values.length;
			ensureExplicitCapacity(size);
			where.append(expressionParser.where());
		}
	}

	/** 表达式中有一部分值可以来自于查询条件的对象，有一部分值可以来自于request、session、当前登录者对象等 */
	public void parseExpression(ReadEvent event) {
		// TODO 这里对表达式进行处理
		for(int i = 0, l = values.length; i < l; i++){
			ExpressionValue ev = values[i];
			parameters[i] = ev.value(event, event.getReader(), parameters[i]);
		}
	}
	
	private void ensureExplicitCapacity(int minCapacity) {
		 //10  1...10
		if(parameters.length > minCapacity){
	        // overflow-conscious code
	        int oldCapacity = parameters.length;
	        int newCapacity = oldCapacity + (oldCapacity >> 1);
	        if (newCapacity - minCapacity < 0)
	            newCapacity = minCapacity;
	        if (newCapacity - MAX_ARRAY_SIZE > 0)
	            newCapacity = hugeCapacity(minCapacity);
	        // minCapacity is usually close to size, so this is a win:
	        parameters = Arrays.copyOf(parameters, newCapacity);
		}
	}
	
	private void _add(Object val){
		ensureExplicitCapacity(size + 1);
		
		parameters[size++] = val;
	}
	
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
	
    @Override
    public Iterator<Object> iterator() {
        return new Itr();
    }

    /**
     * An optimized version of AbstractList.Itr
     */
    private class Itr implements Iterator<Object> {
        int cursor;       // index of next element to return

        public boolean hasNext() {
            return cursor != size;
        }

        public Object next() {
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = StandardFinder.this.parameters;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return elementData[i];
        }

        public void remove() {
        	//nothing to do
        }
    }
    
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }

	public ASMQueryParser getAsmParser() {
		
		return new ASMQueryParser(){

			@Override
			public void internalAnd(String pre, String name, String opt, Object value){
				where.append(" and ").append(pre).append('.').append(name).append(opt);
				_add(value);
			}

			@Override
			public void internalNull(String pre, String name){
				where.append(" and ").append(pre).append('.').append(name).append(" is null");
			}

			@Override
			public String internalJoin(String pre, String name, String alias) {
				return join(pre, name, alias);
			}

			@Override
			public void initernalPageable(Pageable _pageable) {
				pageable = _pageable;			
			}

			@Override
			public boolean internalChecked(String name, Object value, boolean propertyNotMapped) {
				//判断这个字段是否在表达式里存在，如果是则表示该字段用于表达式，不需要自动解析到查询条件里
				for(int i = 0, l = values.length; i < l; i++){
					ExpressionValue ev = values[i];
					if(ev instanceof ExpressionObject && ((ExpressionObject) ev).checkName(name)){
						parameters[i] = value;
						return true;
					}
				}
				return propertyNotMapped;
			}

			@Override
			public void internalOrder(String sn, String on) {
				__order(sn, on);
			}
		};
	}
	
	private int initialCapacity = 10;
	
	public StandardFinder(ProxyEntityManager manager){
		this.manager = manager;
		this.orderby = new StringBuilder();
		this.where = new StringBuilder();
		this.from = new StringBuilder();
		this.parameters = new Object[initialCapacity];
	}
	
	public void setHandler(FinderHandler handler) {
		this.handler = handler;
	}
	
	public void setPageable(Pageable pageable) {
		this.pageable = pageable;
	}
	
	public String join(String pr, String jo, String alias){
		String pn = pr + '.' + jo;
		String pv = null;
		if(null == joinMapped){
			joinMapped = new HashMap<String, String>();
		}else{
			pv = joinMapped.get(pn);
			if(null != pv){
				return pv;
			}
		}
		if(StringHelper.isNotEmpty(alias)){
			pv = alias;
		}else{
			pv = "x_" + joinMapped.size();
		}
		joinMapped.put(pn, pv);
		//from.append(",").append(pn).append(" left join ").append(pv);
		from.append(" left join ").append(pn).append(" ").append(pv);
		return pv;
	}

	/** 如果是可排序的,则第一个排序的方式是按x.ordinal进行排序,后面再追加排序字段,则只能在x.ordinal相同里二次排序 */
	@Override
	public Finder order(String sn, String on) {
		__order(sn, on);
		return this;
	}
	
	@Override
	public List<Item> items() {
		return __items(DEFAULT_SELECT_FIELDS);
	}

	@Override
	public List<Item> items(String selectFields) {
		return __items(selectFields);
	}

	public List<Item> __items(String selectFields) {
		String ql = __merge(new StringBuilder("select new ").append(Item.class.getName()).append("(").append(selectFields).append(") "), "").toString();
		return manager.resultList(Item.class, ql, this);
	}
	
	private StringBuilder __merge(StringBuilder ql, String extAnd){
		ql.append(from).append(where).append(extAnd);
		if(orderby.length() > 0){
			ql.append(" order by ").append(orderby);
		}
		return ql;
	}

	@Override
	public List<Node> nodes() {
		return __treeNodes(DEFAULT_SELECT_FIELDS);
	}

	@Override
	public List<Node> nodes(String selectFields) {
		return __treeNodes(selectFields);
	}

	public List<Node> __treeNodes(String selectFields) {
		List<Node> nodes = __nodes(selectFields);
		//组织成树形结构
		Map<String, Node> tree = new HashMap<String, Node>();
		for(Node node : nodes){
			tree.put(node.getId(), node);
		}
		return __nodes(nodes, tree);
	}

	private List<Node> __nodes(String selectFields) {
		String ql = __merge(new StringBuilder("select new ").append(Node.class.getName()).append("(").append(selectFields).append(",x.parent.id) "), "").toString();
		List<Node> nodes = manager.resultList(Node.class, ql, this);
		//整理一下，生成树
		Map<String, Node> maps = new HashMap<String, Node>();
		for(Node node : nodes){
			maps.put(node.getId(), node);
		}
		return __nodes(nodes, maps);
	}

	@Override
	public List<AjaxNode> ajaxNodes() {
		return __ajaxNodes(DEFAULT_SELECT_FIELDS);
	}

	@Override
	public List<AjaxNode> ajaxNodes(String selectFields) {
		return __ajaxNodes(selectFields);
	}

	public List<AjaxNode> __ajaxNodes(String selectFields) {
		String ql = __merge(new StringBuilder("select new ").append(AjaxNode.class.getName()).append("(").append(selectFields).append(",x.size) "), "").toString();
		return manager.resultList(AjaxNode.class, ql, this);
	}
	
	private void __order(String sn, String on) {
		if (allowAppendOrder && !StringHelper.isEmpty(sn)){
			orderby.append(orderby.length() > 0 ? ",x." : " x.").append(sn).append("desc".equalsIgnoreCase(on) ? " desc" : " asc");
		}
	}
	
	protected String internalSelect(String extAnd){
		return internalSelect(selectField(), extAnd);
	}	
	protected String internalSelect(){
		return internalSelect(selectField(), "");
	}
	
	protected String internalSelect(String fields, String extAnd){
		return __merge(new StringBuilder("select ").append(fields), extAnd).toString();
	}
	
	protected String inernalCount(){
		return new StringBuilder("select count(x)").append(from).append(where).toString();
	}

	protected String selectField(){
		return "x";
	}
	
	protected List<Object> __query(String extAnd){
		return manager.resultList(internalSelect(extAnd), this);
	}
	
	protected List<Object> __query(){
		return manager.resultList(internalSelect(), this);
	}

	@Override
	public List<Object> getList() throws Exception {
		return __handler(__query());	
	}
	
	/**
	 * 在子类中可以被重写
	 * @param query
	 * @return
	 * @throws Exception 
	 */
	protected List<Object> __handler(List<Object> rls) throws Exception{
		return __handler0(rls);
	}
	
	private List<Object> __handler0(List<Object> rls) throws Exception{
		if(handler == null){
			return rls;
		}
		List<Object> items = new ArrayList<Object>();
		for(Object rl : rls){
			Object it = handler.doHandler(rl, rl);
			if(null != it){
				items.add(it);
			}
		}
		return items;
	}
	
	@Override
	public List<Object> getList(String fields) throws Exception {
		return __handler0(manager.resultList(internalSelect(fields), this));
	}

	@Override
	public Page getPage() throws Exception {
		if(null == pageable){
			return new Page(__handler(__query()));
		}
		Page page = manager.resultPage(internalSelect(), inernalCount(), pageable, this);
		return page.convert(__handler(page.getRows()));
	}
	
	@Override
	public Finder and(String and) {
		where.append(" and ").append(and);
		return this;
	}

	@Override
	public Finder and(String and, Object para) {
		_add(para);
		return and(and);
	}
	
	@Override
	public Finder and(String and, Object para, Object para2) {
		_add(para);
		_add(para2);
		return and(and);
	}

	@Override
	public Finder and(String and, Object... paras) {
		for(Object oj : paras){
			_add(oj);
		}
		return and(and);
	}

	@Override
	public Finder or(String or) {
		where.append(" or ").append(or);
		return this;
	}

	@Override
	public Finder or(String or, Object para) {
		_add(para);
		return or(or);
	}

	@Override
	public Finder or(String or, Object... paras) {
		for(Object oj : paras){
			_add(oj);
		}
		return or(or);
	}

	@Override
	public List<Item> items(ItemSelectedFilter filter) {
		return __items(DEFAULT_SELECT_FIELDS, filter);
	}

	@Override
	public List<Item> items(String selectFields, ItemSelectedFilter filter) {
		return __items(selectFields, filter);
	}

	public List<Item> __items(String selectFields, ItemSelectedFilter filter) {
		List<Item> items = __items(selectFields);
		for(Item item : items){
			if(filter.doFilter(item)){
				item.setSelected(true);
			}
		}
		return items;
	}

	@Override
	public List<Node> nodes(ItemSelectedFilter filter) {
		return __nodes(DEFAULT_SELECT_FIELDS, filter);
	}

	@Override
	public List<Node> nodes(String selectFields, ItemSelectedFilter filter) {
		return __nodes(selectFields, filter);
	}

	public List<Node> __nodes(String selectFields, ItemSelectedFilter filter) {
		String ql = __merge(new StringBuilder("select new ").append(Node.class.getName()).append("(").append(selectFields).append(",x.parent.id) "), "").toString();
		List<Node> nodes = manager.resultList(Node.class, ql, this);
		//整理一下，生成树
		Map<String, Node> maps = new HashMap<String, Node>();
		for(Node node : nodes){
			if(filter.doFilter(node)){
				node.setChecked(true);
			}
			maps.put(node.getId(), node);
		}
		return __nodes(nodes, maps);
	}
	
	private List<Node> __nodes(List<Node> nodes, Map<String, Node> tree){
		List<Node> tns = new ArrayList<Node>();
		for(Node node : nodes){
			String pid = node.getParentId();
			if(null != pid){
				Node parent = tree.get(pid);
				if(null != parent){
					if(null == parent.getChildren()){
						parent.setChildren(new ArrayList<Node>());
					}
					parent.getChildren().add(node);
				}else{//非根节点，但是找不到上级父节点；有可能父节点已经被删除，但没删除父节点下的子节点的情况
					//TODO 如何处理这种情况？
					tns.add(node);
				}
			}else{//表示在根节点下
				tns.add(node);
			}
		}
		return tns;
	}

	@Override
	public List<AjaxNode> ajaxNodes(ItemSelectedFilter filter) {
		return __ajaxNodes(DEFAULT_SELECT_FIELDS, filter);
	}

	@Override
	public List<AjaxNode> ajaxNodes(String selectFields, ItemSelectedFilter filter) {
		return __ajaxNodes(selectFields, filter);
	}

	public List<AjaxNode> __ajaxNodes(String selectFields, ItemSelectedFilter filter) {
		List<AjaxNode> nodes = __ajaxNodes(selectFields);
		for(AjaxNode node : nodes){
			if(filter.doFilter(node)){
				node.setChecked(true);
			}
		}
		return nodes;
	}

	@Override
	public List<Object> tryLoadRoot() throws Exception {
		return new ArrayList<>(__root());
	}

	@Override
	public List<Object> tryLoadChildren(Long rid) throws Exception {
		if(null != rid && rid > 0){
			return new ArrayList<>(__node(__childrenExpression(), rid));
		}else{
			return new ArrayList<>(__root());
		}
	}
	
	protected int __childrenExpression(){
		and("x.parent.id=?", 0L);
		return size - 1;
	}
	
	protected List<?> __root() throws Exception{ return null; }

	protected <T> List<T> __node(int i, Long rid) throws Exception{ return null; }
}